<!DOCTYPE html>


<html lang="en">
  

    <head>
      <meta charset="utf-8" />
        
      <meta
        name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1"
      />
      <title>《JavaScript高级程序设计》- 第八章：对象、类与面向对象编程 |  欢迎</title>
  <meta name="generator" content="hexo-theme-ayer">
      
      <link rel="shortcut icon" href="/favicon.ico" />
       
<link rel="stylesheet" href="/dist/main.css">

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css"
      />
      
<link rel="stylesheet" href="/css/custom.css">
 
      <script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>
       
 

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bulma@5.0.1/bulma.min.css"
      />
      <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.19/dist/sweetalert2.min.js"></script>

      <!-- mermaid -->
      
      <style>
        .swal2-styled.swal2-confirm {
          font-size: 1.6rem;
        }
      </style>
    <link rel="alternate" href="/atom.xml" title="欢迎" type="application/atom+xml">
</head>
  </html>
</html>


<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-JavaScript学习/《JavaScript高级程序设计》- 第八章：对象、类与面向对象编程"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  《JavaScript高级程序设计》- 第八章：对象、类与面向对象编程
</h1>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2022/02/17/JavaScript%E5%AD%A6%E4%B9%A0/%E3%80%8AJavaScript%E9%AB%98%E7%BA%A7%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E3%80%8B-%20%E7%AC%AC%E5%85%AB%E7%AB%A0%EF%BC%9A%E5%AF%B9%E8%B1%A1%E3%80%81%E7%B1%BB%E4%B8%8E%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/" class="article-date">
  <time datetime="2022-02-17T15:40:43.000Z" itemprop="datePublished">2022-02-17</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JavaScript%E5%AD%A6%E4%B9%A0/">JavaScript学习</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> Word count:</span>
            <span class="post-count">8k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> Reading time≈</span>
            <span class="post-count">36 min</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <h2 id="第八章：对象、类与面向对象编程"><a href="#第八章：对象、类与面向对象编程" class="headerlink" title="第八章：对象、类与面向对象编程"></a>第八章：对象、类与面向对象编程</h2><h3 id="8-1-对象"><a href="#8-1-对象" class="headerlink" title="8.1 对象"></a>8.1 对象</h3><blockquote>
<p>个人理解：具有特定属性和行为的Object实例</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="comment">// 属性</span></span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>:<span class="string">&#x27;21&#x27;</span>,</span><br><span class="line">    <span class="attr">job</span>:<span class="string">&#x27;student&#x27;</span>,</span><br><span class="line">    <span class="function"><span class="title">sayName</span>(<span class="params"></span>)</span>&#123;		<span class="comment">// 行为</span></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">person.sayName();	<span class="comment">// zyzc</span></span><br></pre></td></tr></table></figure>


</blockquote>
<h4 id="8-1-1-属性的类型"><a href="#8-1-1-属性的类型" class="headerlink" title="8.1.1 属性的类型"></a>8.1.1 属性的类型</h4><blockquote>
<p>ECMA-262使用<code>内部特性</code>来描述属性的<code>特征</code>，特征的表达方式：<code>&#123;特征描述&#125;</code></p>
</blockquote>
<blockquote>
<p>属性的分类</p>
<ol>
<li><p><code>数据属性</code>包含一个保存数据值的位置，数据的读写是通过对这个位置的读写操作，有<code>4个特征描述</code>：</p>
<blockquote>
<p>修改特征描述，必须使用<code>Object.defineProperty()</code>；</p>
</blockquote>
<ul>
<li><p>[[Configurable]]：表示属性是否可以通过delete删除并重新定义，是否可以修改特性，是否可以将其改为访问器访问。直接定义属性的时候，默认为true</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">age</span>:<span class="number">21</span>,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(person,<span class="string">&#x27;age&#x27;</span>,&#123;</span><br><span class="line">	<span class="attr">configurable</span>:<span class="literal">false</span>,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">delete</span> person.age;</span><br><span class="line"><span class="built_in">console</span>.log(person.age);	<span class="comment">// 21</span></span><br><span class="line"><span class="keyword">try</span>&#123;</span><br><span class="line">    <span class="built_in">Object</span>.defineProperty(person,<span class="string">&#x27;age&#x27;</span>,&#123;</span><br><span class="line">		<span class="attr">configurable</span>:<span class="literal">true</span>,</span><br><span class="line">	&#125;)</span><br><span class="line">&#125;<span class="keyword">catch</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&quot;修改为不可设置后，不能再变回可设置&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li><p>[[Enumerable]]：表示是否可以通过<code>for-in</code>循环返回，直接定义属性的时候，默认为true</p>
</li>
<li><p>[[Writable]]：表示属性值是否可以修改，直接定义属性的时候，默认为true</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">age</span>:<span class="number">21</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(person,<span class="string">&#x27;age&#x27;</span>,&#123;</span><br><span class="line">    <span class="attr">writable</span>:<span class="literal">false</span>,</span><br><span class="line">    <span class="attr">value</span>:<span class="number">22</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`修改前<span class="subst">$&#123;person.age&#125;</span>`</span>);	<span class="comment">// 22</span></span><br><span class="line">      </span><br><span class="line">person.age = <span class="number">18</span>;	<span class="comment">// 如果是严格模式下，会报错</span></span><br><span class="line">      </span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`修改后<span class="subst">$&#123;person.age&#125;</span>`</span>);	<span class="comment">// 22</span></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(person,<span class="string">&#x27;age&#x27;</span>,&#123;</span><br><span class="line">    <span class="attr">value</span>:<span class="number">18</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">`再次修改后<span class="subst">$&#123;person.age&#125;</span>`</span>);	<span class="comment">// 18</span></span><br></pre></td></tr></table></figure></li>
<li><p>[[Value]]：属性的值，默认为undefined</p>
</li>
</ul>
</li>
<li><p><code>访问器属性</code>：不包含数据值，通过<code>getter</code>和<code>setter</code>函数来访问与设置，同时也<code>4个特征描述</code>:</p>
<ul>
<li>[[Configurable]]：表示属性是否可以通过delete删除并重新定义，是否可以修改特性，是否可以将其改为数据属性。直接定义属性的时候，默认为true</li>
<li>[[Enumerable]]：表示是否可以通过<code>for-in</code>循环返回，直接定义属性的时候，默认为true</li>
<li>[[Get]]：读取属性的时候调用</li>
<li>[[Set]]：写入属性的时候调用</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> book = &#123;</span><br><span class="line">    <span class="attr">_year</span>:<span class="number">2022</span>, <span class="comment">// 听说是程序员间的约定俗成 _xxx为私有变量，表示为不希望外部直接访问</span></span><br><span class="line">    <span class="attr">edition</span>:<span class="number">1</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(book,<span class="string">&quot;year&quot;</span>,&#123;</span><br><span class="line">    <span class="function"><span class="title">get</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>._year;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="function"><span class="title">set</span>(<span class="params">newValue</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(newValue &gt; <span class="built_in">this</span>._year)&#123;</span><br><span class="line">            <span class="built_in">this</span>.edition += newValue - <span class="built_in">this</span>._year;</span><br><span class="line">            <span class="built_in">this</span>._year = newValue;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(book.year);</span><br><span class="line"><span class="built_in">console</span>.log(book.edition);</span><br><span class="line"></span><br><span class="line">book.year = <span class="number">2024</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(book.year);</span><br><span class="line"><span class="built_in">console</span>.log(book.edition);</span><br></pre></td></tr></table></figure></li>
</ol>
</blockquote>
<h4 id="8-1-2-定义多属性"><a href="#8-1-2-定义多属性" class="headerlink" title="8.1.2 定义多属性"></a>8.1.2 定义多属性</h4><blockquote>
<p>使用<code>Object.defineProperties()</code>定义多属性：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">_birthday</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">sex</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">Object</span>.defineProperties(person,&#123;</span><br><span class="line">    <span class="attr">_birthday</span>:&#123;</span><br><span class="line">        <span class="attr">value</span>:<span class="string">&quot;2000/1/1&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">sex</span>:&#123;</span><br><span class="line">       <span class="attr">value</span>:<span class="string">&#x27;male&#x27;</span>,</span><br><span class="line">       <span class="attr">writable</span>:<span class="literal">false</span>, </span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">birthday</span>:&#123;</span><br><span class="line">        <span class="function"><span class="title">get</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">this</span>._birthday;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="function"><span class="title">set</span>(<span class="params">newValue</span>)</span>&#123;</span><br><span class="line">            <span class="built_in">this</span>._birthday = newValue + <span class="string">&quot;&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line">person.sex = <span class="string">&#x27;female&#x27;</span>;</span><br><span class="line">person.birthday = <span class="string">&#x27;2000/12/12&#x27;</span>;</span><br><span class="line"><span class="built_in">console</span>.log(person.sex);		<span class="comment">// male</span></span><br><span class="line"><span class="built_in">console</span>.log(person.birthday);	<span class="comment">// 2000/12/12</span></span><br></pre></td></tr></table></figure>



<h4 id="8-1-3-读取属性特征"><a href="#8-1-3-读取属性特征" class="headerlink" title="8.1.3 读取属性特征"></a>8.1.3 读取属性特征</h4><blockquote>
<p>使用<code>Object.getOwnPropertyDescriptor(aimObject,descriptor)</code>方法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">_birthday</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">sex</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">Object</span>.defineProperties(person,&#123;</span><br><span class="line">    <span class="attr">_birthday</span>:&#123;</span><br><span class="line">        <span class="attr">value</span>:<span class="string">&quot;2000/1/1&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">sex</span>:&#123;</span><br><span class="line">       <span class="attr">value</span>:<span class="string">&#x27;male&#x27;</span>,</span><br><span class="line">       <span class="attr">writable</span>:<span class="literal">false</span>, </span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">birthday</span>:&#123;</span><br><span class="line">        <span class="function"><span class="title">get</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">this</span>._birthday;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="function"><span class="title">set</span>(<span class="params">newValue</span>)</span>&#123;</span><br><span class="line">            <span class="built_in">this</span>._birthday = newValue + <span class="string">&quot;&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> descriptor = <span class="built_in">Object</span>.getOwnPropertyDescriptor(person,<span class="string">&quot;birthday&quot;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(descriptor.value);  <span class="comment">// undefined</span></span><br><span class="line"><span class="built_in">console</span>.log(descriptor.get)     <span class="comment">// [Function:get]</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> descriptor.get)  <span class="comment">// function</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>ES7新增了<code>Object.getOwnPropertyDescriptors(aimObject)</code>静态方法，获取所有特征描述</p>
</blockquote>
</blockquote>
<h4 id="8-1-4-合并对象"><a href="#8-1-4-合并对象" class="headerlink" title="8.1.4 合并对象"></a>8.1.4 合并对象</h4><blockquote>
<p>又称为<code>混入（mixin）</code>；</p>
<p>ES6专门提供了<code>Object.assgin(aimObj,[sourceObj1,...,sourceObjN])</code>方法，每个<code>源对象</code>中可枚举、自有属性都会复制到<code>目标对象</code>上。</p>
</blockquote>
<h4 id="8-1-5-增强的对象语法"><a href="#8-1-5-增强的对象语法" class="headerlink" title="8.1.5 增强的对象语法"></a>8.1.5 增强的对象语法</h4><ol>
<li><p><code>属性简写</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> name = <span class="string">&#x27;zyzc&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="comment">// 原来写法：name:name,</span></span><br><span class="line">    <span class="comment">// 简写：</span></span><br><span class="line">    name	<span class="comment">// 如果没有找到同名变量会报错</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(person.name);	<span class="comment">//zyzc</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>代码压缩程序</code>会在<code>不同作用域</code>保留属性名，防止找不到属性，可以如下操作：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">makePerson</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        name</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> person = makePerson(<span class="string">&#x27;zyzc&#x27;</span>);</span><br></pre></td></tr></table></figure>

<p>个人感觉：有一点创建类的味道</p>
</blockquote>
</li>
<li><p><code>可计算属性</code>：可以<code>动态命名属性</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> nameKey = <span class="string">&#x27;name&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> ageKey = <span class="string">&#x27;age&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    [nameKey]:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    [ageKey]:<span class="number">21</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(person);	<span class="comment">// &#123; name: &#x27;zyzc&#x27;, age: 21 &#125;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>当然这种<code>动态命名属性</code>还可以使用函数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> nameKey = <span class="string">&#x27;name&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> ageKey = <span class="string">&#x27;age&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> index = <span class="number">0</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getNameKey</span>(<span class="params">key</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">`<span class="subst">$&#123;nameKey&#125;</span>_<span class="subst">$&#123;++index&#125;</span>`</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    [getNameKey(nameKey)]:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    [ageKey]:<span class="number">21</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(person);	<span class="comment">// &#123; name_1: &#x27;zyzc&#x27;, age: 21 &#125;</span></span><br></pre></td></tr></table></figure>

</blockquote>
</li>
<li><p><code>简写方法名字</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">sayName</span>: <span class="function"><span class="keyword">function</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;This is my name&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> student = &#123;</span><br><span class="line">    <span class="function"><span class="title">sayName</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;This is my name&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>简写方法名</code>可以和<code>可计算属性</code>一起使用</p>
</blockquote>
</li>
</ol>
<h4 id="8-1-6-对象解构"><a href="#8-1-6-对象解构" class="headerlink" title="8.1.6 对象解构"></a>8.1.6 对象解构</h4><p>ES6新增的对象解构语法，可以一个语句，实现多个赋值操作。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>:<span class="number">21</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> &#123; <span class="attr">name</span>:MyName,<span class="attr">age</span>:MyAge &#125; = person;	<span class="comment">//MyName=guan MyAge=21;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<blockquote>
<p>同时，在解构赋值的时候，也可以定义默认值</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>:<span class="number">21</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> &#123; <span class="attr">name</span>:MyName,<span class="attr">age</span>:MyAge,MyJob=<span class="string">&quot;font-end&quot;</span> &#125; = person;	</span><br><span class="line"><span class="comment">//MyName=guan MyAge=21 MyJob=&#x27;font-end&#x27;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：<code>null</code>和<code>undefined</code>不能被解构，会被抛出错误</p>
</blockquote>
</blockquote>
<blockquote>
<p>解构的用法：</p>
<ol>
<li><p><code>嵌套解构</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> personCopy = &#123;&#125;;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>:<span class="number">21</span>,</span><br><span class="line">    <span class="attr">job</span>:&#123;</span><br><span class="line">        <span class="attr">title</span>:<span class="string">&#x27;font-end&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">(&#123;</span><br><span class="line">    <span class="attr">name</span>:personCopy.name,</span><br><span class="line">    <span class="attr">age</span>:personCopy.age,</span><br><span class="line">    <span class="attr">job</span>:personCopy.job</span><br><span class="line">&#125; = person);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(personCopy);</span><br><span class="line"><span class="comment">// &#123; name: &#x27;zyzc&#x27;, age: 21, job: &#123; title: &#x27;font-end&#x27; &#125; &#125;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<blockquote>
<p>由于job是一个对象，而两个person对象中，都指向了同一个job对象。</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">personCopy.job.title = <span class="string">&#x27;back-end&#x27;</span>;</span><br><span class="line"><span class="built_in">console</span>.log(personCopy);	</span><br><span class="line"><span class="comment">// &#123; name: &#x27;zyzc&#x27;, age: 21, job: &#123; title: &#x27;back-end&#x27; &#125; &#125;</span></span><br><span class="line"><span class="built_in">console</span>.log(person);</span><br><span class="line"><span class="comment">//	&#123; name: &#x27;zyzc&#x27;, age: 21, job: &#123; title: &#x27;back-end&#x27; &#125; &#125;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>可以进一步对对象中的对象进行解构</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> &#123; <span class="attr">job</span>:&#123; title &#125; &#125; = person;</span><br><span class="line"><span class="built_in">console</span>.log(title);	<span class="comment">// font-end</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>不能对未定义的属性进行嵌套解构</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> &#123; <span class="attr">foo</span>:&#123; message &#125; &#125; = person;	<span class="comment">// 报错</span></span><br></pre></td></tr></table></figure></blockquote>
</li>
<li><p><code>部分解构</code></p>
<p>对象的解构过程，不需要按照对象属性的定义顺序进行。</p>
<blockquote>
<p>解构会按着顺序进行，如果过程中某个属性解构报错，则终止解构，导致解构只完成一部分。</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> personCopy = &#123;&#125;;</span><br><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>:<span class="number">21</span>,</span><br><span class="line">    <span class="attr">job</span>:&#123;</span><br><span class="line">        <span class="attr">title</span>:<span class="string">&#x27;font-end&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>&#123;</span><br><span class="line">    (&#123;</span><br><span class="line">        <span class="attr">name</span>:personCopy.name,</span><br><span class="line">        <span class="attr">sex</span>:personCopy.sex,		<span class="comment">// 虽然元对象没有该属性，但是可以获取为undefined</span></span><br><span class="line">        <span class="attr">foo</span>:&#123; <span class="attr">bar</span>:personCopy.bar &#125;,	<span class="comment">// 进行了会报错的嵌套解构</span></span><br><span class="line">        <span class="attr">age</span>:personCopy.age,</span><br><span class="line">        <span class="attr">job</span>:personCopy.job</span><br><span class="line">    &#125; = person);</span><br><span class="line">&#125;<span class="keyword">catch</span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(personCopy);</span><br><span class="line"><span class="comment">// &#123; name: &#x27;zyzc&#x27;, age: 21, job: &#123; title: &#x27;font-end&#x27; &#125; &#125;</span></span><br></pre></td></tr></table></figure></li>
<li><p><code>参数上下文匹配</code></p>
<p>在参数列表中，也可以进行解构赋值。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line">    <span class="attr">age</span>:<span class="number">21</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printPerson</span>(<span class="params">id,&#123; name , age&#125;</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">arguments</span>);</span><br><span class="line">    <span class="built_in">console</span>.log(name,age);</span><br><span class="line">&#125;</span><br><span class="line">printPerson(<span class="number">1</span>,person);</span><br><span class="line"><span class="comment">//	[Arguments] &#123; &#x27;0&#x27;: 1, &#x27;1&#x27;: &#123; name: &#x27;zyzc&#x27;, age: 21 &#125; &#125;</span></span><br><span class="line"><span class="comment">//	zyzc 21</span></span><br></pre></td></tr></table></figure></li>
</ol>
</blockquote>
<h3 id="8-2-创建对象"><a href="#8-2-创建对象" class="headerlink" title="8.2 创建对象"></a>8.2 创建对象</h3><p>对象虽然可以通过<code>构建函数</code>、<code>字面量表达</code>可以方便创建对象，但是明显不足的是：创建具有<code>同样接口</code>的多个对象需要编写很多重复性代码。</p>
<h4 id="8-2-1-工厂模式"><a href="#8-2-1-工厂模式" class="headerlink" title="8.2.1 工厂模式"></a>8.2.1 工厂模式</h4><blockquote>
<p>虽然减少了重复性代码的问题，但是又新增了一个<code>对象标识问题</code>：新创建的对象是什么类型？</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createPerson</span>(<span class="params">name,age,job</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> o = <span class="keyword">new</span> <span class="built_in">Object</span>();</span><br><span class="line">    o.name = name;</span><br><span class="line">    o.age = age;</span><br><span class="line">    o.job = job;</span><br><span class="line">    o.sayName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> o;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</blockquote>
<h4 id="8-2-2-构造函数模式"><a href="#8-2-2-构造函数模式" class="headerlink" title="8.2.2 构造函数模式"></a>8.2.2 构造函数模式</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name,age,job</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.name = name;</span><br><span class="line">    <span class="built_in">this</span>.age = age;</span><br><span class="line">    <span class="built_in">this</span>.job = job;</span><br><span class="line">    <span class="built_in">this</span>.sayName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> person = <span class="keyword">new</span> Person(<span class="string">&#x27;zyzc&#x27;</span>,<span class="number">21</span>,<span class="string">&#x27;font-end&#x27;</span>);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>当调用new创建对象的时候，会执行如下操作：</p>
<ol>
<li>在内存中创建新对象</li>
<li>新对象内部的[[Prototype]]赋值为构造函数的prototype属性</li>
<li>将<code>this</code>指向刚刚创建的对象</li>
<li>执行构造函数内部的代码（给新的对象添加属性）</li>
<li>返回该对象</li>
</ol>
</blockquote>
<blockquote>
<p>构造函数的特点</p>
<ol>
<li><p>构造函数也是函数：构造函数与函数唯一区别就是<code>调用方法</code>不同</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 作为构造函数</span></span><br><span class="line"><span class="keyword">let</span> person = <span class="keyword">new</span> Person(<span class="string">&#x27;zyzc&#x27;</span>,<span class="number">21</span>,<span class="string">&#x27;student&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 作为函数</span></span><br><span class="line">Person(<span class="string">&#x27;student1&#x27;</span>,<span class="number">18</span>,<span class="string">&#x27;stduent&#x27;</span>);	<span class="comment">// 添加到了window对象</span></span><br><span class="line"><span class="built_in">window</span>.sayName();	<span class="comment">// student1</span></span><br></pre></td></tr></table></figure></li>
<li><p>构造函数的问题：每次创建对象实例的时候，需要将其<code>定义的方法</code>都创建一遍。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name,age,job</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.name = name;</span><br><span class="line">    <span class="built_in">this</span>.age = age;</span><br><span class="line">    <span class="built_in">this</span>.job = job;</span><br><span class="line">    <span class="comment">/* this.sayName = function()&#123;</span></span><br><span class="line"><span class="comment">        console.log(this.name);</span></span><br><span class="line"><span class="comment">    &#125; */</span></span><br><span class="line">    <span class="comment">// 等价于</span></span><br><span class="line">    <span class="built_in">this</span>.sayName = <span class="keyword">new</span> <span class="built_in">Function</span>(<span class="string">&quot;console.log(this.name)&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>不妨将函数提取出来，这样所有Person实例对象，都会指向这个外部函数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name,age,job</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.name = name;</span><br><span class="line">    <span class="built_in">this</span>.age = age;</span><br><span class="line">    <span class="built_in">this</span>.job = job;</span><br><span class="line">    <span class="built_in">this</span>.sayName = sayname;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="title">sayName</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">this</span>.name)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>但是这样做，会混乱<code>全局作用域</code>。这个问题有更好的解决方法——使用<code>原型模式</code>来解决</p>
</blockquote>
</li>
</ol>
</blockquote>
<h4 id="8-2-3-原型模式"><a href="#8-2-3-原型模式" class="headerlink" title="8.2.3 原型模式"></a>8.2.3 原型模式</h4><p><code>原型对象</code>，它上面定义的属性和方法可以被<code>对象实例</code>共享。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>) </span>&#123;&#125;;</span><br><span class="line">Person.prototype.name = <span class="string">&#x27;zyzc&#x27;</span>;</span><br><span class="line">Person.prototype.sayName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> personA = <span class="keyword">new</span> Person();</span><br><span class="line">personA.sayName();	<span class="comment">// zyzc</span></span><br><span class="line"><span class="keyword">let</span> personB = <span class="keyword">new</span> Person();</span><br><span class="line">personB.sayName();	<span class="comment">// zyzc</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>所以可以使用原型模式，解决<code>8.2.2</code>中的问题</p>
</blockquote>
<ol>
<li>关于<code>原型的理解</code>方面</li>
</ol>
<blockquote>
<ol>
<li><p>只要<code>创建函数</code>，都会有一个<code>prototype</code>属性，指向<code>原型对象</code>。<code>原型对象</code>则会有一个<code>constructor</code>属性，指向<code>构造函数</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line"><span class="built_in">console</span>.log(Person.prototype.constructor === Person);	<span class="comment">// true</span></span><br></pre></td></tr></table></figure></li>
<li><p>每次 调用<code>构造函数</code>创建一个新的实例，该实例内部的<code>prototype指针</code>都会指向该实例的<code>原型对象</code></p>
</li>
<li><p>每个实例对象都可以通过<code>__proto__</code>属性访问<code>原型对象</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line"><span class="keyword">let</span> person = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="built_in">console</span>.log(person.__proto__ === Person.prototype);		<span class="comment">// true</span></span><br></pre></td></tr></table></figure></li>
<li><p>所有<code>对象实例</code>都会共享<code>原型对象</code>上的属性和方法【8.2.3开头讲到过】</p>
</li>
</ol>
<blockquote>
<p>注意：</p>
<pre><code>1. 正常的原型链都会终止于`Object`的原型对象
1. `Object`的原型对象是`null`
</code></pre>
</blockquote>
</blockquote>
<ol start="2">
<li>关于<code>原型层级</code>方面：</li>
</ol>
<blockquote>
<p>在通过对象<code>访问属性</code>的时候，会按照该属性进行搜索，先搜索实例对象本身，然后到其原型，再到其原型的原型，直到<code>Object</code>或在搜索途中找到该属性。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line">Person.prototype.name = <span class="string">&#x27;zyzc&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> person1 = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="keyword">let</span> person2 = <span class="keyword">new</span> Person();</span><br><span class="line"></span><br><span class="line">person1.name = <span class="string">&#x27;student&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(person1.name);	<span class="comment">// student</span></span><br><span class="line"><span class="built_in">console</span>.log(person2.name);	<span class="comment">// zyzc</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>person1的name属性，在搜索<code>实例对象本身</code>的时候，就搜索到了name属性的值，所以输出<code>student</code>；由此可知，我们可以使用<code>同名属性</code>遮蔽<code>原型上的默认值</code>。当然，如果要恢复<code>实例对象</code>和<code>原型对象</code>之间的关联，需要<code>delete</code>掉person1上的name属性才可以。</p>
</blockquote>
</blockquote>
<ol start="3">
<li>关于<code>原型对象的一些方法</code>：</li>
</ol>
<blockquote>
<ul>
<li><code>Object.isPrototypeOf()</code>：判断是不是其原型</li>
<li><code>Object.getPrototypeOf()</code>：获取原型对象</li>
<li><code>Object.create()</code>：创建一个原型的新对象</li>
<li><code>Object.hasOwnProperty()</code>：判断属性是否在实例上</li>
<li><code>Object.keys()</code>：列出对象可枚举属性【枚举顺序因浏览器而异】</li>
<li><code>Object.getOwnPropertyNames()</code>：列出对象所有属性</li>
<li><code>Object.getOwnPropertySymbols()</code>：列出对象的符号属性</li>
<li><code>Object.values()</code>：返回对象值数组</li>
<li><code>Object.entries()</code>：返回对象键值对数组</li>
</ul>
</blockquote>
<ol start="4">
<li>重写对象原型：</li>
</ol>
<blockquote>
<p>改造前：每次都要写object.prototype.property，显得繁琐</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">Person.prototype.job = <span class="string">&#x27;student&#x27;</span></span><br><span class="line">Person.prototype.sayName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第一次重写：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">Person.prototype = &#123;</span><br><span class="line">    <span class="attr">job</span>:<span class="string">&#x27;student&#x27;</span>,</span><br><span class="line">    <span class="function"><span class="title">sayName</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="built_in">this</span>.name)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>虽然说这样可以减少代码量，但是会出现一个问题：未声明<code>constructor</code>且无指向。</p>
</blockquote>
<p>第二次重写：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">Person.prototype = &#123;</span><br><span class="line">    <span class="attr">constructor</span>:Person,</span><br><span class="line">    <span class="attr">job</span>:<span class="string">&#x27;student&#x27;</span>,</span><br><span class="line">    <span class="function"><span class="title">sayName</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="built_in">this</span>.name)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>别忘了，constructor有一个默认的特性：<code>不可枚举</code></p>
</blockquote>
<p>第三次重写：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">Person.prototype = &#123;</span><br><span class="line">    <span class="attr">job</span>:<span class="string">&#x27;student&#x27;</span>,</span><br><span class="line">    <span class="function"><span class="title">sayName</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="built_in">this</span>.name)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(Person.prototype,<span class="string">&quot;constructor&quot;</span>,&#123;</span><br><span class="line">	<span class="attr">enumerable</span>:<span class="literal">false</span>,</span><br><span class="line">    <span class="attr">value</span>:Person</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>


</blockquote>
<ol start="5">
<li>重写原型与动态属性、方法</li>
</ol>
<blockquote>
<p>因为原型上<code>搜索值</code>是<code>动态的</code>，所以修改原型的属性、方法都<code>会在实例上反映出来</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line"><span class="keyword">let</span> friend = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="comment">// 修改原型的方法</span></span><br><span class="line">Person.prototype.sayHi = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;hi&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line">friend.sayHi();	<span class="comment">// hi</span></span><br></pre></td></tr></table></figure>

<p>但是如果<code>重写对象原型</code>，就<code>不会在实例上反映出来</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line"><span class="keyword">let</span> friend = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="comment">// 重写原型的方法</span></span><br><span class="line">Person.prototype = &#123;</span><br><span class="line">    <span class="function"><span class="title">sayHello</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;Hello&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(Person.prototype,<span class="string">&quot;constructor&quot;</span>,&#123;</span><br><span class="line">	<span class="attr">enumerable</span>:<span class="literal">false</span>,</span><br><span class="line">    <span class="attr">value</span>:Person</span><br><span class="line">&#125;)</span><br><span class="line">friend.sayHello();	<span class="comment">// TypeError: friend.sayHello is not a function</span></span><br></pre></td></tr></table></figure>

<p>因为实例的<code>[[Prototype]]指针</code>实在调用<code>构造函数</code>的时候自动指向原型的；<code>重写原型</code>就相当于写了一个<code>新的原型</code>，而实例仍然指向原来的原型。</p>
<blockquote>
<p>综上：实例只有指向原型的指针，没有指向构造函数的指针</p>
</blockquote>
</blockquote>
<ol start="6">
<li>原生对象原型</li>
</ol>
<blockquote>
<p>对于原始对象而言，也可以修改或添加新的属性和方法。但是<strong>不推荐使用</strong>，因为会造成冲突！</p>
<p>一般<strong>推荐使用</strong>自定义类。</p>
</blockquote>
<ol start="7">
<li>原型存在的问题：</li>
</ol>
<blockquote>
<p>在原型模式上，主要的问题就是：<strong>包含引用值的属性</strong>！</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">Person.prototype = &#123;</span><br><span class="line"> 	<span class="attr">name</span>:<span class="string">&#x27;zyzc&#x27;</span>,</span><br><span class="line"> 	<span class="attr">age</span>:<span class="number">21</span>,</span><br><span class="line"> 	<span class="attr">job</span>:<span class="string">&#x27;student&#x27;</span>,</span><br><span class="line">     <span class="attr">friends</span>:[<span class="string">&#x27;tom&#x27;</span>,<span class="string">&#x27;john&#x27;</span>],</span><br><span class="line"> 	<span class="function"><span class="title">sayName</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">     	<span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line"> 	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(Person.prototype,<span class="string">&quot;constructor&quot;</span>,&#123;</span><br><span class="line">	<span class="attr">enumerable</span>:<span class="literal">false</span>,</span><br><span class="line"> <span class="attr">value</span>:Person</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> studentA = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="keyword">let</span> studentB = <span class="keyword">new</span> Person();</span><br><span class="line"></span><br><span class="line">studentA.friends.push(<span class="string">&#x27;mike&#x27;</span>);	<span class="comment">// 学生A新认识了mike同学</span></span><br><span class="line"><span class="built_in">console</span>.log(studentA.friends);	<span class="comment">// [ &#x27;tom&#x27;, &#x27;john&#x27;, &#x27;mike&#x27; ]</span></span><br><span class="line"><span class="built_in">console</span>.log(studentB.friends);	<span class="comment">// [ &#x27;tom&#x27;, &#x27;john&#x27;, &#x27;mike&#x27; ]</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>为什么<code>学生B</code>也认识了<code>mike同学</code>，原因是：他们两个的<code>friends</code>属性都<code>指向了同一个数组</code>！</p>
<p>所以在实际开发中，不单独使用<code>原型模式</code></p>
</blockquote>
</blockquote>
<h3 id="8-3-继承"><a href="#8-3-继承" class="headerlink" title="8.3 继承"></a>8.3 继承</h3><p>面向对象语言都支持两种继承：<code>接口继承</code>和<code>实现继承</code>，由于函数没有标签，所以只能<code>实现继承</code>。<code>实现继承</code>是ECMAScript中唯一支持的继承方式，主要通过<code>原型链</code>实现。</p>
<h4 id="8-3-1-原型链"><a href="#8-3-1-原型链" class="headerlink" title="8.3.1 原型链"></a>8.3.1 原型链</h4><p>ECMA-262把<code>原型链</code>定义为<code>主要继承方法</code>。其基本思想就是：通过原型继承多个引用类型的属性和方法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SuperObject</span>(<span class="params"></span>)</span>&#123;     <span class="comment">// 定义对象A</span></span><br><span class="line">    <span class="built_in">this</span>.property = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line">SuperObject.prototype.getSuperValue = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;     <span class="comment">// 为对象A原型添加方法A</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.property;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SubObject</span>(<span class="params"></span>)</span>&#123;       <span class="comment">// 定义对象B</span></span><br><span class="line">    <span class="built_in">this</span>.flag = <span class="literal">false</span>;      </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 让对象B继承对象A</span></span><br><span class="line">SubObject.prototype = <span class="keyword">new</span> SuperObject();</span><br><span class="line"><span class="comment">// 给对象B的原型添加方法B</span></span><br><span class="line">SubObject.prototype.getSubValue = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.flag;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建对象B的实例对象</span></span><br><span class="line"><span class="keyword">let</span> b = <span class="keyword">new</span> SubObject();</span><br><span class="line"><span class="built_in">console</span>.log(b.getSuperValue()); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>



<blockquote>
<p>实际上，所有引用类都有一个<code>最终原型Object</code></p>
</blockquote>
<blockquote>
<p>注意：</p>
</blockquote>
<ol>
<li>原型与继承的关系</li>
</ol>
<blockquote>
<p>如果存在继承关系，则可以通过原型链上的一些操作来判断</p>
<ul>
<li>使用<code>instanceof</code>，<code>实例对象</code>与<code>原型链上的所有构造函数</code>的运算，返回true。</li>
</ul>
 <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(b <span class="keyword">instanceof</span> <span class="built_in">Object</span>);		<span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(b <span class="keyword">instanceof</span> SuperObject);	<span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(b <span class="keyword">instanceof</span> SubObject);	<span class="comment">// true</span></span><br></pre></td></tr></table></figure>

<ul>
<li>使用<code>Object.isPrototypeOf()</code>方法，<code>实例对象</code>与<code>原型对象</code>的运算，返回true</li>
</ul>
 <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Object</span>.prototype.isPrototypeOf(b));			<span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(SuperObject.prototype.isPrototypeOf(b));	<span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(SubObject.prototype.isPrototypeOf(b));		<span class="comment">// true</span></span><br></pre></td></tr></table></figure>
</blockquote>
<ol start="2">
<li>关于<code>方法</code></li>
</ol>
<blockquote>
<p>当<code>实例对象</code>需要<code>覆盖原型的方法</code>或<code>添加新的方法</code>，必须在<code>原型赋值后</code>再操作</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SuperObject</span>(<span class="params"></span>)</span>&#123;     <span class="comment">// 定义对象A</span></span><br><span class="line">    <span class="built_in">this</span>.property = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line">SuperObject.prototype.getSuperValue = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;     <span class="comment">// 为对象A原型添加方法A</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.property;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SubObject</span>(<span class="params"></span>)</span>&#123;       <span class="comment">// 定义对象B</span></span><br><span class="line">    <span class="built_in">this</span>.flag = <span class="literal">false</span>;      </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 让对象B继承对象A(原型赋值)</span></span><br><span class="line">SubObject.prototype = <span class="keyword">new</span> SuperObject();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 给对象B的原型添加方法B</span></span><br><span class="line">SubObject.prototype.getSubValue = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.flag;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 覆盖对象A的原型的方法</span></span><br><span class="line">SubObject.prototype.getSuperValue = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> b = <span class="keyword">new</span> SubObject();</span><br><span class="line"><span class="built_in">console</span>.log(b.getSuperValue());		<span class="comment">// false</span></span><br></pre></td></tr></table></figure>
</blockquote>
<ol start="3">
<li>关于字面量创建原型</li>
</ol>
<blockquote>
<p>由于使用字面量创建原型的方法，就相当于重写了原型链，所以不可以使用子面量创建原型。【<code>在8.2.3第五点提到过</code>】</p>
</blockquote>
<ol start="4">
<li>原型链问题（1）</li>
</ol>
<blockquote>
<p>其实原型链的问题，也就是在原型模式问题的基础之上的拓展。</p>
<p>原型模式中，当属性为<code>引用类型</code>时，会导致<code>属性共享</code>。</p>
<p>在原型链中，一个普通对象，声明了<code>引用类型</code>，当其变为另一个对象的原型后，这个影响就进一步扩散了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SuperObject</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.friends = [<span class="string">&#x27;tom&#x27;</span>,<span class="string">&#x27;john&#x27;</span>];  <span class="comment">// 本来只是一个对象的引用类型属性</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SubObject</span>(<span class="params"></span>)</span>&#123;&#125;  </span><br><span class="line"></span><br><span class="line"><span class="comment">// 让对象B继承对象A(原型赋值)</span></span><br><span class="line">SubObject.prototype = <span class="keyword">new</span> SuperObject();    <span class="comment">// 将friends提升到了原型的引用类型属性</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 给对象B的原型添加方法B</span></span><br><span class="line">SubObject.prototype.makeFriend = <span class="function"><span class="keyword">function</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.friends.push(name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> SubObject();</span><br><span class="line"><span class="keyword">let</span> b = <span class="keyword">new</span> SubObject();</span><br><span class="line"></span><br><span class="line">a.makeFriend(<span class="string">&#x27;mike&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a.friends);	<span class="comment">// [ &#x27;tom&#x27;, &#x27;john&#x27;, &#x27;mike&#x27; ]</span></span><br><span class="line"><span class="built_in">console</span>.log(b.friends);	<span class="comment">// [ &#x27;tom&#x27;, &#x27;john&#x27;, &#x27;mike&#x27; ]</span></span><br></pre></td></tr></table></figure>
</blockquote>
<ol start="5">
<li>原型链问题（2）</li>
</ol>
<blockquote>
<p>子类在实例化的时候，无法给父类的构造函数传参。</p>
</blockquote>
<h4 id="8-3-2-盗用构造函数"><a href="#8-3-2-盗用构造函数" class="headerlink" title="8.3.2 盗用构造函数"></a>8.3.2 盗用构造函数</h4><p>为了解决<code>原型链包含引用类型</code>导致的继承问题，可以采用<code>盗用构造函数</code>的技术来解决。</p>
<blockquote>
<p>其<strong>基本思路</strong>就是：采用<code>call()</code>或<code>apply()</code>在子类构造函数中，调用父类构造函数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SuperObject</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.friends = [<span class="string">&#x27;tom&#x27;</span>,<span class="string">&#x27;john&#x27;</span>];  <span class="comment">// 本来只是一个对象的引用类型属性</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SubObject</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    SuperObject.call(<span class="built_in">this</span>);</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    	等价于</span></span><br><span class="line"><span class="comment">    	this.friends = [&#x27;tom&#x27;,&#x27;john&#x27;]</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">&#125;  </span><br><span class="line"><span class="comment">// 给对象B的原型添加方法B</span></span><br><span class="line">SubObject.prototype.makeFriend = <span class="function"><span class="keyword">function</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.friends.push(name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> SubObject();</span><br><span class="line"><span class="keyword">let</span> b = <span class="keyword">new</span> SubObject();</span><br><span class="line">a.makeFriend(<span class="string">&#x27;mike&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a.friends);	<span class="comment">// [ &#x27;tom&#x27;, &#x27;john&#x27;, &#x27;mike&#x27; ]</span></span><br><span class="line"><span class="built_in">console</span>.log(b.friends);	<span class="comment">// [ &#x27;tom&#x27;, &#x27;john&#x27; ]</span></span><br></pre></td></tr></table></figure>
</blockquote>
<p>除了解决<code>引用类型属性</code>的问题，<code>盗用构造函数</code>还实现了子类实例化的时候，可以给父类的构造函数传参。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name,sex</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.name = name;</span><br><span class="line">    <span class="built_in">this</span>.sex = sex;</span><br><span class="line">    <span class="built_in">this</span>.type = <span class="string">&#x27;human&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line">Person.prototype.sayHi = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;hi&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Student</span>(<span class="params">id,name,sex</span>)</span>&#123;</span><br><span class="line">    <span class="comment">// 伪继承</span></span><br><span class="line">    Person.call(<span class="built_in">this</span>,name,sex);</span><br><span class="line">    <span class="built_in">this</span>.id = id;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> studentA = <span class="keyword">new</span> Student(<span class="number">1</span>,<span class="string">&#x27;zyzc&#x27;</span>,<span class="string">&#x27;male&#x27;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(studentA);	<span class="comment">//Student &#123; name: &#x27;zyzc&#x27;, sex: &#x27;male&#x27;, type: &#x27;human&#x27;, id: 1 &#125;</span></span><br></pre></td></tr></table></figure>



<blockquote>
<p><code>盗用构造函数</code>存在问题：</p>
<ol>
<li><p>子类不能访问父类的原型对象</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(studentA.__proto__ === Student.prototype);	<span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(studentA.__proto__.__proto__ === Person.prototype);	<span class="comment">// false</span></span><br></pre></td></tr></table></figure></li>
<li><p>由于不能访问父类的原型对象 ，所以需要在构造函数内定义方法。</p>
</li>
</ol>
</blockquote>
<h4 id="8-3-3-组合继承"><a href="#8-3-3-组合继承" class="headerlink" title="8.3.3 组合继承"></a>8.3.3 组合继承</h4><p>又称<code>伪经典继承</code>，其综合了<code>原型链</code>和<code>盗用构造函数</code>来完成。</p>
<blockquote>
<p>其基本思想：使用<code>原型链</code>继承原型上的属性和方法；通过<code>盗用构造函数</code>继承实例属性。</p>
<p>这样即可以<code>把方法定义在原型上以实现重用</code>又可以<code>让每个实例拥有自己的属性</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name,age</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.name = name;</span><br><span class="line">    <span class="built_in">this</span>.age = age;</span><br><span class="line">    <span class="built_in">this</span>.friends = [<span class="string">&#x27;tom&#x27;</span>,<span class="string">&#x27;john&#x27;</span>];</span><br><span class="line">&#125;</span><br><span class="line">Person.prototype.sayHi = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;Hi&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Student</span>(<span class="params">id,name,age</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.id = id;</span><br><span class="line">    <span class="comment">// 盗用构造函数，实现属性继承</span></span><br><span class="line">    Person.call(<span class="built_in">this</span>,name,age);</span><br><span class="line">&#125;</span><br><span class="line">Student.prototype = <span class="keyword">new</span> Person();	<span class="comment">// 原型链继承，实现原型对象继承</span></span><br><span class="line">Student.prototype.makeFriend = <span class="function"><span class="keyword">function</span>(<span class="params">newFriendName</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.firends.push(newFriendName)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> studentA = <span class="keyword">new</span> Student(<span class="number">1</span>,<span class="string">&#x27;aaa&#x27;</span>,<span class="number">21</span>);</span><br><span class="line"><span class="keyword">let</span> studentB = <span class="keyword">new</span> Student(<span class="number">2</span>,<span class="string">&#x27;bbb&#x27;</span>,<span class="number">21</span>);</span><br><span class="line"></span><br><span class="line">student</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</blockquote>
<h4 id="8-3-4-原型式继承"><a href="#8-3-4-原型式继承" class="headerlink" title="8.3.4 原型式继承"></a>8.3.4 原型式继承</h4><blockquote>
<p>出发点：<code>不自定义类型</code>，也可以通过原型实现对象之间的<code>信息共享</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">object</span>(<span class="params">o</span>)</span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Temp</span>(<span class="params"></span>)</span>&#123;&#125;	<span class="comment">// 定义一个媒介</span></span><br><span class="line">    Temp.prototype = o;	<span class="comment">// 将传入对象作为媒介的原型</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Temp();	<span class="comment">// 返回&#x27;父类&#x27;的&#x27;子类&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> Person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">friends</span>:[<span class="string">&#x27;tom&#x27;</span>,<span class="string">&#x27;john&#x27;</span>],</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> personA = object(Person);</span><br><span class="line">personA.name = <span class="string">&#x27;personA&#x27;</span>;</span><br><span class="line">personA.friends.push(<span class="string">&#x27;mike&#x27;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(personA.name);		<span class="comment">// personA</span></span><br><span class="line"><span class="built_in">console</span>.log(personA.friends)	<span class="comment">// [ &#x27;tom&#x27;, &#x27;john&#x27;, &#x27;mike&#x27; ]</span></span><br></pre></td></tr></table></figure>

<p>显然，如果遇到了<code>引用类型</code>属性，还是会暴露出问题，毕竟也是原型式的。</p>
<p>再者，可以通过<code>Object.create()</code>方法实现，效果一样的：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> Person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">    <span class="attr">friends</span>:[<span class="string">&#x27;tom&#x27;</span>,<span class="string">&#x27;john&#x27;</span>],</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> personA = <span class="built_in">Object</span>.create(Person,&#123;</span><br><span class="line">    <span class="attr">name</span>:&#123;</span><br><span class="line">        <span class="attr">value</span>:<span class="string">&#x27;personA&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="built_in">console</span>.log(personA.name);	<span class="comment">// personA</span></span><br></pre></td></tr></table></figure>
</blockquote>
<blockquote>
<p>总结：<code>原型式继承</code>适合不需要单独创建构造函数，仍需要在对象间共享信息的场合</p>
</blockquote>
<h4 id="8-3-5-寄生式继承"><a href="#8-3-5-寄生式继承" class="headerlink" title="8.3.5 寄生式继承"></a>8.3.5 寄生式继承</h4><blockquote>
<p>其基本思想：类似于<code>寄生构造函数</code>和<code>工厂模式</code>的结合体，创建一个实现继承的函数，以某种方式<code>增强对象</code>[可以理解为给对象添加属性、方法增强其功能]，然后返回该对象。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createPersonPlus</span>(<span class="params">original</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> temp = <span class="built_in">Object</span>.create(original);		<span class="comment">// 创建一个媒介</span></span><br><span class="line">    temp.sayHi = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;	<span class="comment">// 增强对象</span></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;Hi!&#x27;</span>);		</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">return</span> temp;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> Person = &#123;</span><br><span class="line">    <span class="attr">name</span>:<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> personA = createPersonPlus(Person);</span><br><span class="line">personA.sayHi();		<span class="comment">// Hi!</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：通过<code>寄生式继承</code>给对象添加函数，会导致函数难以重用，与构造函数模式类似。</p>
</blockquote>
</blockquote>
<h4 id="8-3-6-寄生式组合继承"><a href="#8-3-6-寄生式组合继承" class="headerlink" title="8.3.6 寄生式组合继承"></a>8.3.6 寄生式组合继承</h4><blockquote>
<p>由于组合式继承存在效率问题：<strong>父类构造函数会被调用两次</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 组合式继承</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SuperObject</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">this</span>.name = name;</span><br><span class="line">&#125;</span><br><span class="line">SuperObject.prototype.sayName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SubObject</span>(<span class="params">name,age</span>)</span>&#123;</span><br><span class="line">    SuperObject.call(<span class="built_in">this</span>);		<span class="comment">// 盗用构造函数，实现属性继承（第二次调用）</span></span><br><span class="line">    <span class="built_in">this</span>.age = age;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">SubObject.prototype = <span class="keyword">new</span> SuperObject();	<span class="comment">// 继承（第一次调用）</span></span><br><span class="line">SubObject.prototype.constructor = SubObject;</span><br></pre></td></tr></table></figure>
</blockquote>
<blockquote>
<p>寄生式组合继承：通过<code>盗用构造函数</code>继承属性，使用<code>混合式原型链</code>继承方法；基本思路是不通过调用父类构造函数给子类原型赋值，而是取得父类原型的一个副本。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 原型式继承</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">object</span>(<span class="params">o</span>)</span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Temp</span>(<span class="params"></span>)</span>&#123;&#125;	<span class="comment">// 定义一个媒介</span></span><br><span class="line">    Temp.prototype = o;	<span class="comment">// 将传入对象作为媒介的原型</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Temp();	<span class="comment">// 返回&#x27;父类&#x27;的&#x27;子类&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">inheritPrototype</span>(<span class="params">subObject,superObject</span>)</span>&#123;</span><br><span class="line">	<span class="keyword">let</span> prototype = object(superObject.prototype);	<span class="comment">// 创建&#x27;父类&#x27;的&#x27;子类&#x27;</span></span><br><span class="line">    prototype.constructor = subObject;	<span class="comment">// 增强对象</span></span><br><span class="line">    subObject.prototype = prototype;	<span class="comment">// 赋值对象</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SuperObject</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">SubObject</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">inheritPrototype(subObject,superObject);</span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>寄生式组合继承</code>算是引用类型继承的<code>最佳模式</code></p>
</blockquote>
</blockquote>
<h3 id="8-4-类"><a href="#8-4-类" class="headerlink" title="8.4 类"></a>8.4 类</h3><p>前面3节，都是围绕着用ES5的特性来模拟类的行为，各策略有优点也有缺点。但是都逃避不过一个：代码显得冗长、混乱的现象。</p>
<p>为了 解决这个问题，ES6引入了<code>class</code>关键字，具有正式定义类的能力。虽然表面上可以正式支持面向对象编程，实际上背后仍然是原型和构造函数的概念。</p>
<h4 id="8-4-1-类的定义"><a href="#8-4-1-类的定义" class="headerlink" title="8.4.1 类的定义"></a>8.4.1 类的定义</h4><p>类的定义有<code>两种</code>主要方式：</p>
<ul>
<li>类声明：<code>class Person &#123;&#125;;</code></li>
<li>类表达式：<code>const Person =  class &#123;&#125;;</code></li>
</ul>
<blockquote>
<p>与函数表达式类似，但是类表达式在他们被求值之前，不能引用；同时也不具备<code>提升</code>的效果。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(FunctionExpression); <span class="comment">// undefined【变量提升了】</span></span><br><span class="line"><span class="keyword">var</span> FunctionExpression = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;&#125;;</span><br><span class="line"><span class="built_in">console</span>.log(FunctionExpression); <span class="comment">// function() &#123;&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(FunctionDeclaration); <span class="comment">// FunctionDeclaration() &#123;&#125;</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">FunctionDeclaration</span>(<span class="params"></span>) </span>&#123;&#125;	<span class="comment">// 【函数提升了】</span></span><br><span class="line"><span class="built_in">console</span>.log(FunctionDeclaration); <span class="comment">// FunctionDeclaration() &#123;&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(ClassExpression); <span class="comment">// undefined【变量提升了】</span></span><br><span class="line"><span class="keyword">var</span> ClassExpression = <span class="class"><span class="keyword">class</span> </span>&#123;&#125;;</span><br><span class="line"><span class="built_in">console</span>.log(ClassExpression); <span class="comment">// class &#123;&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(ClassDeclaration); <span class="comment">// ReferenceError: ClassDeclaration is not defined</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ClassDeclaration</span> </span>&#123;&#125;	<span class="comment">// 【类定义不会提升】</span></span><br><span class="line"><span class="built_in">console</span>.log(ClassDeclaration); <span class="comment">// class ClassDeclaration &#123;&#125;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>类受块作用域限制</p>
</blockquote>
</blockquote>
<p>类的构成：</p>
<blockquote>
<p>类包含：构造函数方法、实例方法、获取函数、设置函数和静态类方法；这些<code>不是必需的</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&gt;<span class="class"><span class="keyword">class</span> <span class="title">Foo</span> </span>&#123;&#125;	<span class="comment">// 空类定义</span></span><br><span class="line">&gt;<span class="class"><span class="keyword">class</span> <span class="title">Bar</span> </span>&#123;</span><br><span class="line">   <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;&#125;	<span class="comment">// 有构造函数的类</span></span><br><span class="line">&gt;&#125;</span><br><span class="line">&gt;<span class="class"><span class="keyword">class</span> <span class="title">Baz</span> </span>&#123;</span><br><span class="line">   <span class="keyword">get</span> <span class="title">myBaz</span>()&#123;&#125;	<span class="comment">// 有获取函数的类</span></span><br><span class="line">&gt;&#125;</span><br><span class="line">&gt;<span class="class"><span class="keyword">class</span> <span class="title">Sub</span> </span>&#123;</span><br><span class="line">   <span class="keyword">set</span> <span class="title">Sub</span>()&#123;&#125;		<span class="comment">// 有设置函数的类</span></span><br><span class="line">&gt;&#125;</span><br><span class="line">&gt;<span class="class"><span class="keyword">class</span> <span class="title">Qux</span> </span>&#123;</span><br><span class="line">   <span class="keyword">static</span> <span class="function"><span class="title">myQux</span>(<span class="params"></span>)</span>&#123;&#125;	<span class="comment">// 有静态方法的类</span></span><br><span class="line">&gt;&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>可以通过<code>类名.name</code>获取类表达式的名称字符串。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> Person = <span class="class"><span class="keyword">class</span> <span class="title">PersonName</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">identify</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(Person.name, PersonName.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line">p.identify(); <span class="comment">// PersonName PersonName</span></span><br><span class="line"><span class="built_in">console</span>.log(Person.name); <span class="comment">// PersonName</span></span><br><span class="line"><span class="built_in">console</span>.log(PersonName); <span class="comment">// ReferenceError: PersonName is not defined</span></span><br></pre></td></tr></table></figure>
</blockquote>
</blockquote>
<h4 id="8-4-2-类构造函数"><a href="#8-4-2-类构造函数" class="headerlink" title="8.4.2 类构造函数"></a>8.4.2 类构造函数</h4><blockquote>
<p><code>constructor</code>用于定义创建类的构造函数；</p>
</blockquote>
<ol>
<li>实例化：</li>
</ol>
<blockquote>
<p>在使用<code>new</code>操作符创建类的时候，调用函数<code>constructor</code>进行<code>实例化</code>；<strong>会执行如下操作：</strong></p>
<ul>
<li>在内存中创建一个新对象</li>
<li>将<code>新对象</code>内部的[[Prototype]]指针赋值为<code>构造函数</code>的prototype属性</li>
<li><code>this</code>指向新的对象</li>
<li>执行构造函数内部代码（给新对象添加属性）</li>
<li>返回该对象</li>
</ul>
</blockquote>
<ol start="2">
<li><code>类构造函数</code>与<code>构造函数</code>的区别：</li>
</ol>
<blockquote>
<p><code>类构造函数</code>必须使用<code>new</code>操作符，不然会报错！</p>
<p><code>普通构造函数</code>如果不使用<code>new</code>调用，那么this指向<code>window对象</code>。</p>
</blockquote>
<ol start="3">
<li>类 = 特殊函数</li>
</ol>
<blockquote>
<p>ECMAScript类就是一种<code>特殊函数</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Person);		<span class="comment">// [class Person]</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> Person);	<span class="comment">// function</span></span><br></pre></td></tr></table></figure>

<p>ECMAScript类也具有<code>prototype</code>属性，该原型的<code>constructor</code>也指向类自身。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Person === Person.prototype.constructor);<span class="comment">// true</span></span><br></pre></td></tr></table></figure>
</blockquote>
<ol start="4">
<li>类也可以作为参数传递</li>
</ol>
<h4 id="8-4-3-实例、原型和类成员"><a href="#8-4-3-实例、原型和类成员" class="headerlink" title="8.4.3 实例、原型和类成员"></a>8.4.3 实例、原型和类成员</h4><p>类的语法，可以定义<code>实例成员</code>、<code>原型成员</code>、<code>类成员</code></p>
<ol>
<li><p>实例成员：在构造函数内部，可以通过<code>this</code>给<code>新创建的实例</code>添加<code>自有属性</code>；即使构造函数执行后，仍然可以继续添加。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.name = <span class="keyword">new</span> <span class="built_in">String</span>(<span class="string">&#x27;zyzc&#x27;</span>);</span><br><span class="line">        <span class="built_in">this</span>.sayName = <span class="function">()=&gt;</span> <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">        <span class="built_in">this</span>.nickName = [<span class="string">&#x27;fff&#x27;</span>,<span class="string">&#x27;yyy&#x27;</span>];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p1 = <span class="keyword">new</span> Person(),</span><br><span class="line">    p2 = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="comment">// 下面的都不相等，说明二者具有‘自有属性’</span></span><br><span class="line"><span class="built_in">console</span>.log(p1.name === p2.name);		<span class="comment">// false</span></span><br><span class="line"><span class="built_in">console</span>.log(p1.sayName === p2.sayName);	<span class="comment">// false</span></span><br><span class="line"><span class="built_in">console</span>.log(p1.nickName === p2.nickName);	<span class="comment">// false</span></span><br></pre></td></tr></table></figure></li>
<li><p>原型方法：<code>类块中定义的方法</code>会成为<code>原型方法</code>，但是不能在<code>类块</code>中给原型添加<code>原始值</code>或<code>对象</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.locate = <span class="function">()=&gt;</span> <span class="built_in">console</span>.log(<span class="string">&#x27;实例调用的&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="title">locate</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;原型调用的&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line">p.locate();	<span class="comment">// 实例调用的</span></span><br><span class="line">Person.prototype.locate();	<span class="comment">// 原型调用的</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>由于类方法等同于对象属性，也可以使用<code>字符串</code>、<code>符号</code>或<code>计算属性</code>作为键</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> symbolKey = <span class="built_in">Symbol</span>(<span class="string">&#x27;symbolKey&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">stringKey</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;这是字符串作为键&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    [symbolKey]()&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;这是符号作为键&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    [<span class="string">&#x27;computed&#x27;</span> + <span class="string">&#x27;Key&#x27;</span>]()&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&quot;这是计算属性作为键&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line">p.stringKey();	<span class="comment">// 这是字符串作为键</span></span><br><span class="line">p[symbolKey]();	<span class="comment">// 这是符号作为键</span></span><br><span class="line">p.computedKey();<span class="comment">// 这是计算属性作为键</span></span><br></pre></td></tr></table></figure></blockquote>
</li>
<li><p>访问器</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>._name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span> <span class="title">name</span>(<span class="params">newName</span>) &#123;</span><br><span class="line">        <span class="built_in">this</span>._name = newName;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title">name</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>._name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person(<span class="string">&#x27;zyzc&#x27;</span>);</span><br><span class="line"><span class="built_in">console</span>.log(p.name);	<span class="comment">// zyzc</span></span><br><span class="line">p.name = <span class="string">&#x27;studentA&#x27;</span>;</span><br><span class="line"><span class="built_in">console</span>.log(p.name);	<span class="comment">// studentA</span></span><br></pre></td></tr></table></figure></li>
<li><p>静态类方法：使用<code>static</code>作为前缀，执行不依赖于实例、类的操作。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.locate = <span class="function">()=&gt;</span> <span class="built_in">console</span>.log(<span class="string">&#x27;实例调用的&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="title">locate</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;原型调用的&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> <span class="function"><span class="title">locate</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;静态类调用的&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line">p.locate();	<span class="comment">// 实例调用的</span></span><br><span class="line">Person.prototype.locate();	<span class="comment">// 原型调用的</span></span><br><span class="line">Person.locate();	<span class="comment">// 静态类调用的</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>静态类方法非常适合作为<code>实例工厂</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params">age</span>)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>._age = age;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="title">sayAge</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="built_in">this</span>._age);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> <span class="function"><span class="title">create</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Person(<span class="built_in">Math</span>.floor(<span class="built_in">Math</span>.random()*<span class="number">100</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p = Person.create();</span><br><span class="line"><span class="built_in">console</span>.log(p);	<span class="comment">// Person &#123; _age: 43 &#125;</span></span><br><span class="line">p.sayAge();		<span class="comment">// 43</span></span><br></pre></td></tr></table></figure></blockquote>
</li>
<li><p>非函数原型成员和类成员</p>
<blockquote>
<p>虽然类块中不能显式添加类成员、原型成员，但是可以在<code>外部手动添加</code>；</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">sayName</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(Person.greeting + <span class="built_in">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 定义类成员</span></span><br><span class="line">Person.greeting = <span class="string">&#x27;Hi!My name is:&#x27;</span>;</span><br><span class="line"><span class="comment">// 定义原型成员</span></span><br><span class="line">Person.prototype.name = <span class="string">&#x27;zyzc&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line">p.sayName();	<span class="comment">// Hi!My name is zyzc</span></span><br></pre></td></tr></table></figure></li>
<li><p>迭代器与生成器方法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 在原型上定义生成器方法</span></span><br><span class="line">    *<span class="function"><span class="title">createNicknameIterator</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">yield</span> <span class="string">&#x27;Jack&#x27;</span>;</span><br><span class="line">        <span class="keyword">yield</span> <span class="string">&#x27;Jake&#x27;</span>;</span><br><span class="line">        <span class="keyword">yield</span> <span class="string">&#x27;J-Dog&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//  在类上定义生成器方法</span></span><br><span class="line">    <span class="keyword">static</span> *<span class="function"><span class="title">createJobIterator</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="keyword">yield</span> <span class="string">&#x27;Butcher&#x27;</span>;</span><br><span class="line">        <span class="keyword">yield</span> <span class="string">&#x27;Baker&#x27;</span>;</span><br><span class="line">        <span class="keyword">yield</span> <span class="string">&#x27;Candlestick maker&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">let</span> jobIter = Person.createJobIterator();</span><br><span class="line"><span class="built_in">console</span>.log(jobIter.next().value); <span class="comment">// Butcher</span></span><br><span class="line"><span class="built_in">console</span>.log(jobIter.next().value); <span class="comment">// Baker</span></span><br><span class="line"><span class="built_in">console</span>.log(jobIter.next().value); <span class="comment">// Candlestick maker</span></span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="keyword">let</span> nicknameIter = p.createNicknameIterator();</span><br><span class="line"><span class="built_in">console</span>.log(nicknameIter.next().value); <span class="comment">// Jack</span></span><br><span class="line"><span class="built_in">console</span>.log(nicknameIter.next().value); <span class="comment">// Jake</span></span><br><span class="line"><span class="built_in">console</span>.log(nicknameIter.next().value); <span class="comment">// J-Dog</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>由于类支持生成器方法，所以可以把类实例，变为可迭代对象</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.nicknames = [<span class="string">&#x27;fff&#x27;</span>,<span class="string">&#x27;yyy&#x27;</span>];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    *[<span class="built_in">Symbol</span>.iterator]() &#123;</span><br><span class="line">        <span class="keyword">yield</span> *<span class="built_in">this</span>.nicknames.entries();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> item <span class="keyword">of</span> p)&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(item);</span><br><span class="line">     <span class="comment">// [ 0, &#x27;fff&#x27; ]</span></span><br><span class="line">	<span class="comment">// [ 1, &#x27;yyy&#x27; ]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>也可以返回迭代器</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.nicknames = [<span class="string">&#x27;fff&#x27;</span>,<span class="string">&#x27;yyy&#x27;</span>];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    [<span class="built_in">Symbol</span>.iterator]() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.nicknames.entries();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> item <span class="keyword">of</span> p)&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(item);	</span><br><span class="line">    <span class="comment">// [ 0, &#x27;fff&#x27; ]</span></span><br><span class="line">	<span class="comment">// [ 1, &#x27;yyy&#x27; ]</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></blockquote>
</li>
</ol>
<h4 id="8-4-4-继承"><a href="#8-4-4-继承" class="headerlink" title="8.4.4 继承"></a>8.4.4 继承</h4><p>虽然ES6有<code>extends</code>关键字支持继承，但其背后依旧使用的是原型链</p>
<ol>
<li>继承基础</li>
</ol>
<blockquote>
<p>ES6支持单继承，不仅仅可以继承类、还可以继承构造函数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;&#125;;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">dog</span> <span class="keyword">extends</span> <span class="title">Animal</span></span>&#123;&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">student</span> <span class="keyword">extends</span> <span class="title">Person</span></span>&#123;&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>由于继承也是通过原型链构造的，也会像一般对象一样，遵循规则。</p>
</blockquote>
</blockquote>
<ol start="2">
<li>super()</li>
</ol>
<blockquote>
<p>派生类可以通过<code>super</code>关键字<code>引用</code>它们的<code>原型</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="function"><span class="title">speak</span>(<span class="params">message</span>)</span>&#123;</span><br><span class="line">    	<span class="built_in">console</span>.log(message);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">        <span class="comment">// 不能再super之前使用this，不然会抛出错误</span></span><br><span class="line">        <span class="built_in">super</span>();	<span class="comment">// 调用了父类的构造函数</span></span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> <span class="function"><span class="title">speak</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">super</span>.speak(<span class="string">&#x27;汪汪汪&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> dogA = <span class="keyword">new</span> Dog(<span class="string">&quot;dogA&quot;</span>);</span><br><span class="line">Dog.speak();</span><br></pre></td></tr></table></figure>

<blockquote>
<p>使用<code>super</code>需要注意以下几点：</p>
<ul>
<li>只能在派生<code>类构造函数</code>和<code>静态方法</code>中使用</li>
<li>不能单独引用<code>super</code>，要么调用构造函数、要么引用静态方法</li>
<li>调用<code>super()</code>会调用<code>父类构造函数</code>，并将返回的实例赋值给<code>this</code></li>
<li><code>super()</code>的行为如同调用<code>父类构造函数</code>，所以可以<code>传入参数</code></li>
<li>如果子类<code>没有定义构造函数</code>，在实例化子类的时候，自动调用<code>super()</code>来替代</li>
<li>在<code>类构造函数</code>中，不能在<code>super()</code>之前引用<code>this</code></li>
<li>子类定义了构造函数，要么调用<code>super()</code>、要么返回一个对象<code>return &#123;&#125;</code></li>
</ul>
</blockquote>
</blockquote>
<ol start="3">
<li>抽象基类</li>
</ol>
<blockquote>
<p>其实就像Java中的<code>抽象类</code>，<code>只能继承</code>，<code>不能被实例化</code>。</p>
<blockquote>
<p>可以通过<code>new.target</code>实现</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>( <span class="keyword">new</span>.target === Animal)&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&#x27;Animal cannot be directly instantiated&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</blockquote>
<p>既然说像Java的<code>抽象类</code>，那也可以定义<code>抽象方法</code>，要求子类<code>必须定义</code>这个<code>抽象方法</code>。</p>
<blockquote>
<p>因为原型方法在调用类构造函数之前就存在了，所以可以采用this来检查。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>( <span class="keyword">new</span>.target === Animal)&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&#x27;Animal cannot be directly instantiated&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>( !<span class="built_in">this</span>.isLive )&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&#x27;Inheriting class must define isLive() out of constructor&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span> <span class="keyword">extends</span> <span class="title">Animal</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="title">isLive</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span></span>&#123;&#125;</span><br><span class="line"><span class="keyword">new</span> Dog();		<span class="comment">// 创建成功</span></span><br><span class="line"><span class="keyword">new</span> Cat();		<span class="comment">// Inheriting class must define isLive() out of constructor</span></span><br></pre></td></tr></table></figure>
</blockquote>
</blockquote>
<ol start="4">
<li>继承内置对象</li>
</ol>
<blockquote>
<blockquote>
<p>通过继承内置对象，可以<code>拓展</code>内置类型。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SuperArray</span> <span class="keyword">extends</span> <span class="title">Array</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">shuffle</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">        <span class="comment">// 添加了洗牌算法</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="built_in">this</span>.length - <span class="number">1</span>; i &gt; <span class="number">0</span>; i--) &#123;</span><br><span class="line">            <span class="keyword">const</span> j = <span class="built_in">Math</span>.floor(<span class="built_in">Math</span>.random() * (i + <span class="number">1</span>));</span><br><span class="line">            [<span class="built_in">this</span>[i], <span class="built_in">this</span>[j]] = [<span class="built_in">this</span>[j], <span class="built_in">this</span>[i]];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> SuperArray(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a <span class="keyword">instanceof</span> <span class="built_in">Array</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(a <span class="keyword">instanceof</span> SuperArray); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(a); <span class="comment">// [1, 2, 3, 4, 5]</span></span><br><span class="line">a.shuffle();</span><br><span class="line"><span class="built_in">console</span>.log(a); <span class="comment">// [3, 1, 4, 5, 2]</span></span><br></pre></td></tr></table></figure>
</blockquote>
<blockquote>
<p>有一些内置类型的方法会<code>返回新的实例</code>，可以通过覆盖<code>Symbol.species</code>访问器，决定返回什么类型的实例</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SuperArray</span> <span class="keyword">extends</span> <span class="title">Array</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> get [<span class="built_in">Symbol</span>.species]()&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">Array</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> a1 = <span class="keyword">new</span> SuperArray(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>);</span><br><span class="line"><span class="keyword">let</span> a2 = a1.filter(<span class="function"><span class="params">x</span> =&gt;</span> !!(x%<span class="number">2</span>));</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a1 <span class="keyword">instanceof</span> SuperArray);	<span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(a1 <span class="keyword">instanceof</span> <span class="built_in">Array</span>);		<span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(a2 <span class="keyword">instanceof</span> SuperArray);	<span class="comment">// false</span></span><br><span class="line"><span class="built_in">console</span>.log(a2 <span class="keyword">instanceof</span> <span class="built_in">Array</span>);		<span class="comment">// true</span></span><br></pre></td></tr></table></figure>
</blockquote>
</blockquote>
<ol start="5">
<li>类混入</li>
</ol>
<blockquote>
<p>把不同类的行为集中到一个类是一种常见的JS模式；虽然没有显示的支持多继承，但是可以模拟这种行为</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;&#125;</span><br><span class="line"><span class="comment">// 定义并使其返回一个&#x27;混合类&#x27;</span></span><br><span class="line"><span class="keyword">let</span> HeadMixin = <span class="function">(<span class="params">Superclass</span>) =&gt;</span> <span class="class"><span class="keyword">class</span> <span class="keyword">extends</span> <span class="title">Superclass</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">head</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;head&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">let</span> BodyMixin = <span class="function">(<span class="params">Superclass</span>) =&gt;</span> <span class="class"><span class="keyword">class</span> <span class="keyword">extends</span> <span class="title">Superclass</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">body</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;body&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> FootMixin = <span class="function">(<span class="params">Superclass</span>) =&gt;</span> <span class="class"><span class="keyword">class</span> <span class="keyword">extends</span> <span class="title">Superclass</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="title">foot</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">&#x27;foot&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">mix</span>(<span class="params">BaseClass,...Mixins</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> Mixins.reduce(<span class="function">(<span class="params">accumulator, current</span>) =&gt;</span> current(accumulator), BaseClass);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 模仿出多继承的行为</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span> <span class="keyword">extends</span> <span class="title">mix</span>(<span class="title">Animal</span>,<span class="title">HeadMixin</span>,<span class="title">BodyMixin</span>,<span class="title">FootMixin</span>)</span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> dog = <span class="keyword">new</span> Dog();</span><br><span class="line">dog.head();		<span class="comment">// head</span></span><br><span class="line">dog.body();		<span class="comment">// body</span></span><br><span class="line">dog.foot();		<span class="comment">// foot</span></span><br></pre></td></tr></table></figure>
</blockquote>
<h3 id="8-5-小结"><a href="#8-5-小结" class="headerlink" title="8.5 小结"></a>8.5 小结</h3><ol>
<li><p>JavaScript的继承主要通过<code>原型链</code>来实现。通过子类可以通过原型链搜索到父类的属性、行为，达到<code>共享的状态</code>。</p>
</li>
<li><p>原型链的问题是：所有继承的属性和方法都会在对象实例间共享，无法做到实例私有。</p>
</li>
<li><p>继承的分类：</p>
<ul>
<li>原型链</li>
<li>盗用构造函数</li>
<li>组合继承【<strong>目前最流行</strong>】</li>
<li>原型式继承</li>
<li>寄生式继承</li>
<li>寄生式组合继承【<strong>最有效</strong>】</li>
</ul>
</li>
<li><p>ES6提供了类、继承的语法，可以优雅地解决这些问题。但是类、继承的<code>本质</code>还是在<code>原型链</code>上。</p>
</li>
</ol>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>Copyright： </strong>
          
          Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=http://example.com/2022/02/17/JavaScript%E5%AD%A6%E4%B9%A0/%E3%80%8AJavaScript%E9%AB%98%E7%BA%A7%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E3%80%8B-%20%E7%AC%AC%E5%85%AB%E7%AB%A0%EF%BC%9A%E5%AF%B9%E8%B1%A1%E3%80%81%E7%B1%BB%E4%B8%8E%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JavaScript/" rel="tag">JavaScript</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/2022/02/17/%E5%AF%92%E5%81%87/%E5%AF%92%E5%81%87%E8%AE%B0%E5%BD%95/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            寒假记录
          
        </div>
      </a>
    
    
      <a href="/2022/02/14/JavaScript%E5%AD%A6%E4%B9%A0/%E3%80%8AJavaScript%E9%AB%98%E7%BA%A7%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E3%80%8B-%20%E7%AC%AC%E5%85%AD%E7%AB%A0%EF%BC%9A%E9%9B%86%E5%90%88%E5%BC%95%E7%94%A8%E7%B1%BB%E5%9E%8B/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">《JavaScript高级程序设计》- 第六章：集合引用类型</div>
      </a>
    
  </nav>

   
<!-- valine评论 -->
<div id="vcomments-box">
  <div id="vcomments"></div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js"></script>
<script>
  new Valine({
    el: "#vcomments",
    app_id: "jeb2pvxjdeJQOj5OG3AUavGv-gzGzoHsz",
    app_key: "6YlB9tQJTstHMM8GOwFu4uyY",
    path: window.location.pathname,
    avatar: "monsterid",
    placeholder: "给我的文章加点评论吧~",
    recordIP: true,
  });
  const infoEle = document.querySelector("#vcomments .info");
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
    infoEle.childNodes.forEach(function (item) {
      item.parentNode.removeChild(item);
    });
  }
</script>
<style>
  #vcomments-box {
    padding: 5px 30px;
  }

  @media screen and (max-width: 800px) {
    #vcomments-box {
      padding: 5px 0px;
    }
  }

  #vcomments-box #vcomments {
    background-color: #fff;
  }

  .v .vlist .vcard .vh {
    padding-right: 20px;
  }

  .v .vlist .vcard {
    padding-left: 10px;
  }
</style>

 
   
     
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2022
        <i class="ri-heart-fill heart_icon"></i> 子与子乘
      </li>
    </ul>
    <ul>
      <li>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>Visitors:<span id="busuanzi_value_site_uv"></span></span>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>Views:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
      </li>
    </ul>
  </div>
</footer>    
    </main>
    <div class="float_btns">
      <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

    </div>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="欢迎"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">友链</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i></p>
  <div class="reward-box">
    
    
  </div>
</div>
    
<script src="/js/jquery-3.6.0.min.js"></script>
 
<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->
 
<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: ".tocbot",
    contentSelector: ".article-entry",
    headingSelector: "h1, h2, h3, h4, h5, h6",
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: "main",
    positionFixedSelector: ".tocbot",
    positionFixedClass: "is-position-fixed",
    fixedSidebarOffset: "auto",
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->
 <!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script> 
<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->
 
<script src="/js/busuanzi-2.3.pure.min.js"></script>
 
<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->
 
<link rel="stylesheet" href="/css/clipboard.css">
 <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>
 
<!-- CanvasBackground -->

<script>
  if (window.mermaid) {
    mermaid.initialize({ theme: "forest" });
  }
</script>


    
    

  </div>
</body>

</html>